namespace OneWorks.Utils.FluentData
{
    using System;
    using System.Collections.Generic;

    internal class SelectBuilder<TEntity> : ISelectBuilder<TEntity>
    {
        public SelectBuilderData Data { get; set; }
        protected ActionsHandler Actions { get; set; }

        public SelectBuilder(IDbCommand command)
        {
            this.Data =  new SelectBuilderData(command, "");
            this.Actions = new ActionsHandler(this.Data);
        }

        private IDbCommand GetPreparedDbCommand()
        {
            if (this.Data.PagingItemsPerPage > 0
                && string.IsNullOrEmpty(this.Data.OrderBy))
                throw new FluentDataException("Order by must defined when using Paging.");

            this.Data.Command.ClearSql.Sql(this.Data.Command.Data.Context.Data.Provider.GetSqlForSelectBuilder(this.Data));
            return this.Data.Command;
        }

        public ISelectBuilder<TEntity> Select(string sql)
        {
            this.Data.Select += sql;
            return this;
        }

        public ISelectBuilder<TEntity> From(string sql)
        {
            this.Data.From += sql;
            return this;
        }

        public ISelectBuilder<TEntity> Where(string sql)
        {
            this.Data.WhereSql += sql;
            return this;
        }

        public ISelectBuilder<TEntity> AndWhere(string sql)
        {
            if(this.Data.WhereSql.Length > 0)
                this.Data.WhereSql += " and ";
            this.Data.WhereSql += sql;
            return this;
        }

        public ISelectBuilder<TEntity> OrWhere(string sql)
        {
            if(this.Data.WhereSql.Length > 0)
                this.Data.WhereSql += " or ";
            this.Data.WhereSql += sql;
            return this;
        }

        public ISelectBuilder<TEntity> OrderBy(string sql)
        {
            this.Data.OrderBy += sql;
            return this;
        }

        public ISelectBuilder<TEntity> GroupBy(string sql)
        {
            this.Data.GroupBy += sql;
            return this;
        }

        public ISelectBuilder<TEntity> Having(string sql)
        {
            this.Data.Having += sql;
            return this;
        }

        public ISelectBuilder<TEntity> Paging(int currentPage, int itemsPerPage)
        {
            this.Data.PagingCurrentPage = currentPage;
            this.Data.PagingItemsPerPage = itemsPerPage;
            return this;
        }

        public ISelectBuilder<TEntity> Parameter(string name, object value, DataTypes parameterType, ParameterDirection direction, int size)
        {
            this.Data.Command.Parameter(name, value, parameterType, direction, size);
            return this;
        }

        public ISelectBuilder<TEntity> Parameters(params object[] parameters)
        {
            this.Data.Command.Parameters(parameters);
            return this;
        }
        public List<TEntity> QueryMany(Action<TEntity, IDataReader> customMapper = null)
        {
            return this.GetPreparedDbCommand().QueryMany<TEntity>(customMapper);
        }

        public List<TEntity> QueryMany(Action<TEntity, dynamic> customMapper)
        {
            return this.GetPreparedDbCommand().QueryMany<TEntity>(customMapper);
        }

        public TList QueryMany<TList>(Action<TEntity, IDataReader> customMapper = null) where TList : IList<TEntity>
        {
            return this.GetPreparedDbCommand().QueryMany<TEntity, TList>(customMapper);
        }

        public TList QueryMany<TList>(Action<TEntity, dynamic> customMapper) where TList : IList<TEntity>
        {
            return this.GetPreparedDbCommand().QueryMany<TEntity, TList>(customMapper);
        }

        public void QueryComplexMany(IList<TEntity> list, Action<IList<TEntity>, IDataReader> customMapper)
        {
            this.GetPreparedDbCommand().QueryComplexMany<TEntity>(list, customMapper);
        }

        public void QueryComplexMany(IList<TEntity> list, Action<IList<TEntity>, dynamic> customMapper)
        {
            this.GetPreparedDbCommand().QueryComplexMany<TEntity>(list, customMapper);
        }

        public TEntity QuerySingle(Action<TEntity, IDataReader> customMapper = null)
        {
            return this.GetPreparedDbCommand().QuerySingle<TEntity>(customMapper);
        }

        public TEntity QuerySingle(Action<TEntity, dynamic> customMapper)
        {
            return this.GetPreparedDbCommand().QuerySingle<TEntity>(customMapper);
        }

        public TEntity QueryComplexSingle(Func<IDataReader, TEntity> customMapper)
        {
            return this.GetPreparedDbCommand().QueryComplexSingle(customMapper);
        }

        public TEntity QueryComplexSingle(Func<dynamic, TEntity> customMapper)
        {
            return this.GetPreparedDbCommand().QueryComplexSingle(customMapper);
        }
    }
}